package com.alogic.pipeline;

import com.alogic.event.*;
import com.alogic.load.Loader;
import com.alogic.uid.IdTool;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.Script;
import com.alogic.xscript.doc.XsObject;
import com.alogic.xscript.doc.json.JsonObject;
import com.anysoft.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.w3c.dom.Element;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

/**
 * 事件服务器
 * @since 1.6.13.35 [20210218 duanyy] <br>
 *
 * @version 1.6.14.3 [20210322 duanyy] <br>
 * - 修复cancel的判断问题 <br>
 */
public class PipelineServer extends EventServer.Abstract implements PipelineListener {
    protected Logiclet onJobCreate = null;
    protected Logiclet onJobStart = null;
    protected Logiclet onJobFinish = null;
    protected Logiclet onStageCreate = null;
    protected Logiclet onStageStart = null;
    protected Logiclet onStageFinish = null;
    protected Logiclet onStepCreate = null;
    protected Logiclet onStepStart = null;
    protected Logiclet onStepFinish = null;
    protected Set<String> cannceledJobs = new HashSet<String>();
    protected Loader<Pipeline> loader = null;

    protected String eventRun = "on.pipeline.run";
    protected String eventCancel = "on.pipeline.cancel";

    @Override
    public void configure(Properties p){
        super.configure(p);
        eventRun = PropertiesConstants.getString(p,"event.run",eventRun);
        eventCancel = PropertiesConstants.getString(p,"event.cancel",eventCancel);
    }


    @Override
    public void start() {

    }

    @Override
    public void stop() {

    }

    @Override
    public void join(long timeout) {

    }

    @Override
    public void handle(Event _data, long timestamp) {
        if (_data.getEventType().equals(eventRun)){
            String runId = _data.getProperty("runId","");
            if (StringUtils.isEmpty(runId)){
                _data.setProperty("$code","core.e1014",true);
                _data.setProperty("$reason","Can not find runId",true);
            }else{
                String pipelineId = _data.getProperty("pipelineId","");
                if (StringUtils.isEmpty(pipelineId)){
                    _data.setProperty("$code","core.e1014",true);
                    _data.setProperty("$reason","Can not find pipelineId",true);
                    dispatch(_data);
                }else{
                    Pipeline pipeline = loader.load(pipelineId,true);
                    if (pipeline == null){
                        _data.setProperty("$code","core.e1014",true);
                        _data.setProperty("$reason","Can not find pipeline:" + pipelineId,true);
                        dispatch(_data);
                    }else{
                        EventProperties ctx = new EventProperties(_data,Settings.get());
                        DefaultProperties props = new DefaultProperties("default",ctx);
                        pipeline.prepare(runId,props,this);
                        pipeline.run(runId,props,this);
                    }
                }
            }
        }else{
            if (_data.getEventType().equals(eventCancel)){
                String runId = _data.getProperty("runId","");
                if (StringUtils.isEmpty(runId)){
                    _data.setProperty("$code","core.e1014",true);
                    _data.setProperty("$reason","Can not find runId",true);
                    dispatch(_data);
                }else{
                    cannceledJobs.add(runId);
                }
            }else{
                dispatch(_data);
            }
        }
    }

    @Override
    public boolean isCanceled(String jobId) {
        return cannceledJobs.contains(jobId);
    }

    @Override
    public String newId() {
        return IdTool.nextId("default");
    }

    @Override
    public void onCreate(String jobId, Properties ctx) {
        if (onJobCreate != null){
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root",new HashMap<String,Object>());
                onJobCreate.execute(doc,doc, logicletContext, null);
            }catch (Exception ex){
                LOG.error(ex.getMessage());
            }
        }
    }

    @Override
    public void onStart(String jobId, Properties ctx) {
        if (onJobStart != null){
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root",new HashMap<String,Object>());
                onJobStart.execute(doc,doc, logicletContext, null);
            }catch (Exception ex){
                LOG.error(ex.getMessage());
            }
        }
    }

    @Override
    public void onFinish(String jobId, Properties ctx) {
        if (onJobFinish != null){
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root",new HashMap<String,Object>());
                onJobFinish.execute(doc,doc, logicletContext, null);
            }catch (Exception ex){
                LOG.error(ex.getMessage());
            }
        }
        cannceledJobs.remove(jobId);
    }

    @Override
    public void onCreate(String jobId, String stageId, Properties ctx) {
        if (onStageCreate != null){
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root",new HashMap<String,Object>());
                onStageCreate.execute(doc,doc, logicletContext, null);
            }catch (Exception ex){
                LOG.error(ex.getMessage());
            }
        }
    }

    @Override
    public void onStart(String jobId, String stageId, Properties ctx) {
        if (onStageStart != null){
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root",new HashMap<String,Object>());
                onStageStart.execute(doc,doc, logicletContext, null);
            }catch (Exception ex){
                LOG.error(ex.getMessage());
            }
        }
    }

    @Override
    public void onFinish(String jobId, String stageId, Properties ctx) {
        if (onStageFinish != null){
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root",new HashMap<String,Object>());
                onStageFinish.execute(doc,doc, logicletContext, null);
            }catch (Exception ex){
                LOG.error(ex.getMessage());
            }
        }
    }

    @Override
    public void onCreate(String jobId, String stageId, String stepId, Properties ctx) {
        if (onStepCreate != null){
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root",new HashMap<String,Object>());
                onStepCreate.execute(doc,doc, logicletContext, null);
            }catch (Exception ex){
                LOG.error(ex.getMessage());
            }
        }
    }

    @Override
    public void onStart(String jobId, String stageId, String stepId, Properties ctx) {
        if (onStepStart != null){
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root",new HashMap<String,Object>());
                onStepStart.execute(doc,doc, logicletContext, null);
            }catch (Exception ex){
                LOG.error(ex.getMessage());
            }
        }
    }

    @Override
    public void onFinish(String jobId, String stageId, String stepId, Properties ctx) {
        if (onStepFinish != null){
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root",new HashMap<String,Object>());
                onStepFinish.execute(doc,doc, logicletContext, null);
            }catch (Exception ex){
                LOG.error(ex.getMessage());
            }
        }
    }

    @Override
    public void configure(Element e, Properties p) {
        Properties props = new XmlElementProperties(e,p);
        configure(props);
        Element elem = XmlTools.getFirstElementByPath(e, this.getHandlerType());
        if (elem != null){
            try {
                sink = EventBus.loadFromElement(elem, props);
            }catch (Exception ex){
                LOG.error(ExceptionUtils.getStackTrace(ex));
                LOG.error("Can not create event handler:" + XmlTools.node2String(elem));
            }
        }

        elem = XmlTools.getFirstElementByPath(e, "on-job-create");
        if (elem != null){
            onJobCreate = Script.create(elem, props);
        }

        elem = XmlTools.getFirstElementByPath(e, "on-job-start");
        if (elem != null){
            onJobStart = Script.create(elem, props);
        }

        elem = XmlTools.getFirstElementByPath(e, "on-job-finish");
        if (elem != null){
            onJobFinish = Script.create(elem, props);
        }

        elem = XmlTools.getFirstElementByPath(e, "on-stage-create");
        if (elem != null){
            onStageCreate = Script.create(elem, props);
        }

        elem = XmlTools.getFirstElementByPath(e, "on-stage-start");
        if (elem != null){
            onStageStart = Script.create(elem, props);
        }

        elem = XmlTools.getFirstElementByPath(e, "on-stage-finish");
        if (elem != null){
            onStageFinish = Script.create(elem, props);
        }

        elem = XmlTools.getFirstElementByPath(e, "on-step-create");
        if (elem != null){
            onStepCreate = Script.create(elem, props);
        }

        elem = XmlTools.getFirstElementByPath(e, "on-step-start");
        if (elem != null){
            onStepStart = Script.create(elem, props);
        }

        elem = XmlTools.getFirstElementByPath(e, "on-step-finish");
        if (elem != null){
            onStepFinish = Script.create(elem, props);
        }

        elem = XmlTools.getFirstElementByPath(e, "loader");
        if (elem != null){
            Factory<Loader<Pipeline>> f = new Factory<Loader<Pipeline>>();
            try {
                loader = f.newInstance(elem, p, "module");
            }catch (Exception ex){
                LOG.error("Can not create loader with " + XmlTools.node2String(elem));
                LOG.error(ExceptionUtils.getStackTrace(ex));
            }
        }
    }
}
